﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace helicopterFight
{
    public class HelicopterObject : GameObject
    {
        private float rotacjaSmigla = 0.0f;
        public float akceleracjaSmigla = 0.0f; //wartosc od 0.001f do 0.1f zwieksza sie o powiedzmy 0.001f
        private bool silnikWlaczony = false;
        private TestState state = null;

        public TestState State
        {
            get { return state; }
            set { state = value; }
        }
        private float maxAkcelSmigla = 0.4f;
        private float incAkcelSmigla = 0.001f;
        private const int maxAltitude = 1000;
        private const int minAltitude = 30;
        private BoundingSphere heliSphere;
        private const float heliSphereRadius = 7;
        private bool isAlive = true;
        private int timeOfDeath;
        public byte playerId;
        public int points = 0;
        public String name = "";
        public bool isColor = false;
        public Vector3 color = new Vector3(1f, 1.0f, 1.0f);


        public bool IsAlive
        {
            get { return isAlive; }
            set {
                    if (!isAlive)
                        return;
                    isAlive = value;
                    if (!isAlive/* && state != null && state.GameTime != null*/)
                        timeOfDeath = state.GameTime.TotalGameTime.Seconds;
                }
        }

        private float speed = 0.0f, 
                      fspeed = 0.0f;
        private char    direction = 'n',
                        direction2 = 'n',
                        dirrot = 'n';
        public bool local = true;

        private bool [] missiles = new bool[16];
        private List<String> missileNames = new List<string>();

        //private Cue missileCue;
        private AudioEmitter emitter = new AudioEmitter();
        private AudioListener listener = new AudioListener();

        private float angle = 0;
        public static float missileDistance = 5;
        public float prevMisDistance = 5;

        private Vector3 CalculateLocation(float angle, float distance)
        {
            return new Vector3(
                (float)Math.Cos(angle) * distance,
                0,
                (float)Math.Sin(angle) * distance);
        }

        public BoundingSphere HeliSphere
        {
            get { return heliSphere; }
            set { heliSphere = value; }
        }

        public void collisionSkinInit()
        {
            heliSphere = new BoundingSphere(position, heliSphereRadius);
        }

        public void init(TestState state)
        {
            this.state = state;
            initMissiles();
        }

        public bool respawn()
        {
            if (!isAlive)
            {
                if (Math.Abs(state.GameTime.TotalGameTime.Seconds - timeOfDeath) > 5)
                {
                    isAlive = true;
                    return true;
                }
                return false;
            }
            return false;
        }

        public void setPosition(Vector3 pos)
        {
            position = pos;
            heliSphere.Center = pos;
            heliSphere.Radius = heliSphereRadius;
        }

        public override void draw()
        {
            if (!isAlive)
                return;

            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            foreach (ModelMesh mesh in model.Meshes)
            {
                if (missileNames.Contains(mesh.Name))
                    if (missiles[missileNames.IndexOf(mesh.Name)] == false)
                        continue;

                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;
                    if (isColor)
                        effect.DiffuseColor = color;

                    effect.World =
                        transforms[mesh.ParentBone.Index] *
                        Matrix.CreateFromYawPitchRoll(
                        rotation.Y,
                        rotation.X,
                        rotation.Z) *

                        Matrix.CreateScale(scale) *

                        Matrix.CreateTranslation(position);


                    if (mesh.Name.Equals("main rotor"))
                        effect.World =
                            Matrix.CreateRotationZ(rotacjaSmigla) *
                        transforms[mesh.ParentBone.Index] *
                        Matrix.CreateFromYawPitchRoll(
                        rotation.Y,
                        rotation.X,
                        rotation.Z) *

                        Matrix.CreateScale(scale) *

                        Matrix.CreateTranslation(position);

                    if (mesh.Name.Equals("tail rotor"))
                        effect.World =
                            Matrix.CreateRotationZ(rotacjaSmigla) *
                        transforms[mesh.ParentBone.Index] *
                        Matrix.CreateFromYawPitchRoll(
                        rotation.Y,
                        rotation.X,
                        rotation.Z) *

                        Matrix.CreateScale(scale) *

                        Matrix.CreateTranslation(position);

                    effect.Projection = cam.CameraProjectionMatrix;
                    effect.View = cam.CameraViewMatrix;
                }
                mesh.Draw();
            }
        }

        public override void update()
        {
            if (!isAlive)
                return;

            angle = 90f;  
            listener.Position = cam.getPos();

            if (missileDistance - prevMisDistance >= 6)
                missileDistance = prevMisDistance + 3;
            
            prevMisDistance = missileDistance;

            emitter.Position = CalculateLocation(angle, missileDistance);
   
            TestState.missileCue.Apply3D(listener, emitter); 

            rotacjaSmigla += akceleracjaSmigla;

            if (!local)
                return;

            if (silnikWlaczony)
            {
                if (akceleracjaSmigla < maxAkcelSmigla)
                    akceleracjaSmigla += incAkcelSmigla;
            }
            else
            {
                if (akceleracjaSmigla > 0)
                    akceleracjaSmigla -= incAkcelSmigla;
            }

            switch (direction)
            {
                case 'u':   if (akceleracjaSmigla > 0.3f && speed < 1.5f)
                                speed += 0.01f;
                            break;
                case 'd':   speed -= 0.1f;
                            break;
                case 'n':   if (akceleracjaSmigla > 0.3f && speed > 0.0f)
                                speed -= 0.1f;
                            else if (akceleracjaSmigla > 0.3f && speed < 0.0f)
                                speed += 0.1f;
                            break;               
            }
            switch (dirrot)
            {
                case 'l':
                    if (position.Y > 31)
                    {
                        rotation.Y += 0.01f;
                        rotation.Z = -0.1f;
                    }
                    break;
                case 'r':
                    if (position.Y > 31)
                    {
                        rotation.Y -= 0.01f;
                        rotation.Z = 0.1f;
                    }
                    break;
                case 'n':
                    rotation.Z = 0.0f;
                    break;
            }

            switch (direction2)
            {
                case 'f':
                    if (fspeed < 3.0f)
                        fspeed += 0.01f + akceleracjaSmigla / 3;
                    break;
                case 'b':
                    if (fspeed > -2.0f)
                        fspeed -= 0.01f + akceleracjaSmigla / 4;
                    break;
                case 'n':
                    if (fspeed > 0.0f)
                        fspeed -= 0.01f + akceleracjaSmigla / 3;
                    if (fspeed < 0.0f)
                        fspeed += 0.01f + akceleracjaSmigla / 3;
                    break;
            }
            position.Y += speed;
            if (position.Y < minAltitude)
            {
                position.Y = minAltitude;
                speed = 0;
            }
            if (position.Y > maxAltitude)
                position.Y = maxAltitude;

            //hmm ciezka matma O.o
            Vector3 xxx = Vector3.Transform(new Vector3(0, 0, fspeed), Matrix.CreateFromYawPitchRoll(
                                        rotation.Y,
                                        0,
                                        0));

            position+=xxx;

            heliSphere.Center = position;
            heliSphere.Radius = heliSphereRadius;

            cam.updateCamera(position,rotation);


            rotation.X = fspeed / 20;            
            if (fspeed > 0)
                position.Y -= fspeed / 2;

            direction = 'n';
            dirrot = 'n';
            direction2 = 'n';

        }

        public void engine(bool action)
        {
            silnikWlaczony = action;
        }
        public void engine()
        {
            silnikWlaczony = !silnikWlaczony;
        }

        public void moveUp()
        {
            direction = 'u';
        }
        public void moveDown()
        {
            direction = 'd';
        }

        public void moveForward()
        {
            direction2 = 'f';
        }

        public void moveBackward()
        {
            direction2 = 'b';
        }

        public void rotateLeft()
        {
            dirrot = 'l';
        }

        public void rotateRight()
        {
            dirrot = 'r';
        }

        public int getMaxAltitude()
        { 
            return maxAltitude;
        }
        public int getMinAltitude()
        {
            return minAltitude;
        }

        public void shootMissile(Network network)
        {
            if (!isAlive)
                return;

            for (int x = 0; x < 16; x++)
            {

                if (missiles[x] == true)
                {
                    missiles[x] = false;
                    launchMissile(network, x);
                    break;
                }
                if (x == 15)
                {
                    emptyMagazine();
                }
            }
            
        }

        public Missile launchMissile(Network network, int x)
        {
            Missile m = new Missile();
            m.init(state.game, this);
            

            Vector3 tmp = Vector3.Transform(new Vector3(0, 0, 1), Matrix.CreateFromYawPitchRoll(rotation.Y, rotation.X, rotation.Z));
            tmp = tmp*m.speed;
            Vector3 tmpPos = position;
            if (x%2 == 0)
                tmpPos.X += 3;
            else
                tmpPos.X -= 3;
            m.setParams(tmpPos, rotation, tmp);
            TestState.missileCue = MenuState.soundBank.GetCue("missile");
            TestState.missileCue.Apply3D(listener, emitter);
            TestState.missileCue.Play();
            state.obiekty.Add(m);

            if (network != null && state.Multiplayer)
            {
                network.addMissile(m);
            }

            return m;
        }

        private void initMissiles()
        {
            missileNames.Add("missilel1");
            missileNames.Add("missiler1");
            missileNames.Add("missilel2");
            missileNames.Add("missiler2");
            missileNames.Add("missilel3");
            missileNames.Add("missiler3");
            missileNames.Add("missilel4");
            missileNames.Add("missiler4");

            for (int x = 0; x < 16; x++)
            {
                missiles[x] = true;
            }
        }

        public void emptyMagazine()
        {
            MenuState.soundBank.PlayCue("empty_mag");
        }

        public int getMissiles()
        {
            int ile = 0; 
            for (int i = 0; i < 16; i++)
            {
                if (missiles[i])
                    ile++;
            }
            return ile;
        }

        public void resetMissiles()
        {
            for (int i = 0; i < 16; i++)
                missiles[i] = true;
        }

        public void resetSpeed()
        {
            this.speed = 0;
            this.fspeed = 0;
        }
    }
}
